package main

import (
	"context"
	"fmt"
	"golang.org/x/sync/errgroup"
	"net/http"
	"os"
	"os/signal"
	"strconv"
)

/**
 * 基于 errgroup 实现一个 http server 的启动和关闭 ，以及 linux signal 信号的注册和处理，
 * 要保证能够一个退出，全部注销退出。
 *
 */
func main() {
	ctx, cancel := context.WithCancel(context.Background())
	group, errCtx := errgroup.WithContext(ctx)

	mux := http.NewServeMux()
	mux.HandleFunc("/", index)

	var server *http.Server
	var err error

	// 启动服务
	group.Go(func() error {
		server, err = startServer(mux, 8080)
		return err
	})

	// 关闭服务
	group.Go(func() error {
		<-errCtx.Done() // 阻塞
		return shutdownServer(ctx, server)
	})

	// linux信号量
	channel := make(chan os.Signal, 1)
	signal.Notify(channel)

	group.Go(func() error {
		for {
			select {
			case <-errCtx.Done():
				return errCtx.Err()
			case <-channel:
				cancel()
			}
		}

		return nil
	})

	if err := group.Wait(); err != nil {
		fmt.Println("group error: ", err)
	}
	fmt.Println("all group shutdown")

}

func index(w http.ResponseWriter, t *http.Request) {
	w.Write([]byte("hello index"))
}

func startServer(mux *http.ServeMux, port int) (*http.Server, error) {
	server := &http.Server{
		Addr:    ":" + strconv.Itoa(port),
		Handler: mux,
	}

	err := server.ListenAndServe()
	if err != nil {
		err = fmt.Errorf("服务启动失败：%w", err)
		return nil, err
	}

	return server, err
}

func shutdownServer(ctx context.Context, server *http.Server) error {
	err := server.Shutdown(ctx)
	if err != nil {
		err = fmt.Errorf("服务关闭失败，%w", err)
		return err
	}

	return nil
}
